package com.aiwiown.snackmq.network.connection;

import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 一个单例类，用于在整个 Broker 中追踪和管理所有活跃的客户端连接。
 * 该类通过维护一个线程安全的映射表来存储和管理 Netty Channel 对象，
 * 提供添加、移除连接以及获取活跃连接数的功能。
 */
@Slf4j
public class ConnectionManager {

    private static final ConnectionManager INSTANCE = new ConnectionManager();

    // 使用 ConcurrentMap 存储活跃连接，键为 Channel 的唯一标识符，值为对应的 Channel 对象
    private final ConcurrentMap<String, Channel> activeConnections = new ConcurrentHashMap<>();
    /**
     * 存储生产者ID与其网络通道的映射。
     * Key: producerId, Value: Channel
     * 这是事务状态回查机制的关键。
     */
    private final Map<String, Channel> producerIdToChannel = new ConcurrentHashMap<>();

    // 私有构造函数，确保单例模式
    private ConnectionManager() {
    }

    /**
     * 获取 ConnectionManager 的唯一实例。
     *
     * @return ConnectionManager 的单例实例
     */
    public static ConnectionManager getInstance() {
        return INSTANCE;
    }

    /**
     * 注册一个生产者。
     *
     * @param producerId 生产者的唯一ID
     * @param channel    生产者对应的网络通道
     */
    public void registerProducer(String producerId, Channel channel) {
        if (producerId != null && !producerId.isEmpty() && channel != null) {
            producerIdToChannel.put(producerId, channel);
            log.info("Registered producer '{}' with channel {}", producerId, channel.id());
        }
    }

    /**
     * 根据生产者ID获取其网络通道。
     *
     * @param producerId 生产者ID
     * @return 对应的 Channel，如果不存在则返回 null
     */
    public Channel getChannelByProducerId(String producerId) {
        return producerIdToChannel.get(producerId);
    }

    /**
     * 当一个新连接建立时，将其添加到管理器中。
     *
     * @param channel 新建立的 Netty Channel，不能为空
     */
    public void addConnection(Channel channel) {
        if (channel != null) {
            // 将 Channel 的唯一标识符作为键，Channel 对象作为值存入映射表
            activeConnections.put(channel.id().asLongText(), channel);
        }
    }

    /**
     * 当一个连接断开时，将其从管理器中移除。
     *
     * @param channel 已断开的 Netty Channel，不能为空
     */
    public void removeConnection(Channel channel) {
        if (channel != null) {
            // 根据 Channel 的唯一标识符从映射表中移除对应的连接
            activeConnections.remove(channel.id().asLongText());
        }
        producerIdToChannel.values().removeIf(ch -> ch.equals(channel));
    }

    /**
     * 获取当前活跃连接的总数。
     * 在返回计数前，会清理掉所有已经不活跃的连接，以确保计数的准确性。
     *
     * @return 活跃连接的数量
     */
    public int getActiveConnections() {
        // 清理掉所有已经不活跃的连接，确保映射表中只包含活跃连接
        activeConnections.values().removeIf(channel -> !channel.isActive());
        // 返回当前活跃连接的数量
        return activeConnections.size();
    }
}
